/*
 *  IncrementalAlgorithm.cpp
 *
 *  Created by Roman Kutlak on 30/10/2010.
 *  Copyright 2010 Roman Kutlak. All rights reserved.
 *
 */

#include "IncrementalAlgorithm.h"

using std::string;
using std::cout;
using std::cerr;
using std::endl;

namespace kutlak {
namespace roman {
namespace gre {
    
#pragma mark -
#pragma mark lifecycle
    
    IncrementalAlgorithm::IncrementalAlgorithm(const pKnowledgeBase& kb, 
                                               const pOntology& ontology) :
    Algorithm(kb, ontology, "Incremental Algorithm") {}
    
    IncrementalAlgorithm::~IncrementalAlgorithm() = default;
    
#pragma mark -
#pragma mark operations
    
    RefExp IncrementalAlgorithm::
    MakeReferringExpression(const EntityPtrT& referent, ContainerT distractors)
    {
        RefExp result;
        PrefOrderT po;
        // check if referent is not null
        if (!referent)
            return result;
        
        if (mPreferenceOrder.size() < 1)
        { // empty preference order
            po = CreatePreferenceOrder(*referent);
            
#ifdef DEBUG
            if (IA_DEBUG > 1)
            {
                for (auto it = po.begin(); it != po.end(); ++it)
                    cerr << *it << " ";
                cerr << endl;
            }
#endif
            
        }
        else
        {
            po = mPreferenceOrder;
        }
        
        // remove the referent from the set if present        
        EntityPtrEqPred pred(referent);
        auto it = std::remove_if(distractors.begin(), distractors.end(), pred);
        distractors.erase(it, distractors.end());;
        
        PrefOrderT::const_iterator nextAttribute = po.begin();
        string nextValue;
        Property nextProp;
        
        while (nextAttribute != po.end())
        { // while there are Attributes in the PO
            
#ifdef DEBUG
            if (IA_DEBUG > 1)
            {
                cerr << "IA::MakeReferringExpression: current Attribute:";
                cerr << *nextAttribute << endl;
            }
#endif
            
            if (referent->HasAttribute(*nextAttribute) &&
                !IsBannedAttribute(*nextAttribute))
            {
                nextProp.SetAttribute(*nextAttribute);
                nextProp.SetValue(referent->ValueForAttribute(*nextAttribute));
                nextProp = FindBestValue(distractors, referent, nextProp);
                
#ifdef DEBUG
                if (IA_DEBUG > 1)
                {
                    cerr << "IA::MakeReferringExpression: current property:";
                    cerr << nextProp << endl;
                }
#endif
                
                if (HasDiscriminatoryPower(distractors, nextProp))
                {
                    
#ifdef DEBUG
                    if (IA_DEBUG > 1)
                        cerr << "IA::MakeReferringExpression: property added.\n";
#endif
                    result.Add(nextProp);
                    Filter(distractors, nextProp);
                    if (distractors.size() == 0)
                        break;
                }
            }
            
            ++nextAttribute;
        }
        
        if (fDeterminer)
        {
            if (distractors.empty())
                result.Prepend(Property("determiner", "definite"));
            else
                result.Prepend(Property("determiner", "indefinite"));
        }
        
        return result;
    }
    
    RefExp IncrementalAlgorithm::
    MakeReferringExpression(const std::string& name)
    {
        return this->Algorithm::MRE(name);
    }
    
#pragma mark -
#pragma mark access
    
    IncrementalAlgorithm::PrefOrderT IncrementalAlgorithm::PreferenceOrder()
    {
        return mPreferenceOrder;
    }
    
    void IncrementalAlgorithm::SetPreferenceOrder(const PrefOrderT& po)
    {
        mPreferenceOrder.clear();
        mPreferenceOrder.insert(mPreferenceOrder.begin(), po.begin(), po.end());
    }
    
#pragma mark -
#pragma mark protected
    IncrementalAlgorithm::PrefOrderT IncrementalAlgorithm::
    CreatePreferenceOrder(const Entity& ref)
    {
        IncrementalAlgorithm::PrefOrderT preferenceOrder;
        
        if (mPreferenceOrder.size() != 0)
            return mPreferenceOrder;
        // default attribute : type
        preferenceOrder.push_back(Ontology::kType);
        
        for (Entity::const_iterator it = ref.begin(); it != ref.end(); ++it)
        {
            Vindex_t att = it->Attribute();
            // don't add the same Attribute more than once
            // although in theory it is possible
            bool add = true;
            for (auto atts = preferenceOrder.begin();
                 atts != preferenceOrder.end(); ++atts)
            {
                if (att == *atts)
                {
                    add = false;
                    break;
                }
            }
            if (add)
                preferenceOrder.push_back(att);
        }
        
        return preferenceOrder;
    }
}
}
}
